package com.zzb.framework.dict.service;

import com.alibaba.fastjson.JSON;
import com.zzb.framework.common.Base;
import com.zzb.framework.common.BaseResponse;
import com.zzb.framework.common.ServiceException;
import com.zzb.framework.dict.entity.SysDict;
import com.zzb.framework.param.service.SysParamService;
import com.zzb.framework.user.utils.SystemUser;
import com.zzb.framework.utils.AnnotationUtil;
import org.apache.commons.beanutils.MethodUtils;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.EnumUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

import java.io.File;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.*;
import java.util.stream.Collectors;

/**
 * Created by zhangzhenbin on 17-7-4.
 */
@Component
public class DictAutoGeneratorComponent extends Base {

    @Autowired
    private SysDictService dictService;
    @Autowired
    private SysParamService sysParamService;

    @Transactional
    public BaseResponse<File> run(String tempFileName) {
        autoUpdate();
        return dictService.generatorJSON(tempFileName);
    }

    public void autoUpdate(){
        String enumsPackage = sysParamService.getString("ENUMS_PACKAGE", "com.zzb.framework.common");
        Set<Class> fileClass = AnnotationUtil.findFileClass(enumsPackage);
        List<SysDict> enumsValueList = new ArrayList<>();
        //数据库中现有的数据字典列表
        List<SysDict> existDicts = dictService.selectAll();
        Map<String,List<SysDict>> existDictMap = new HashMap<>();
        Map<String,List<SysDict>> enumsDictMap = new HashMap<>();
        existDicts.forEach(sysDict -> {
            if(!existDictMap.containsKey(sysDict.getParamKey())){
                existDictMap.put(sysDict.getParamKey(),new ArrayList<>());
            }
            existDictMap.get(sysDict.getParamKey()).add(sysDict);
        });

        //扫描包，并放入existDicts中
        if(CollectionUtils.isNotEmpty(fileClass)){
            fileClass.forEach(aClass -> {
                if (aClass.isEnum()) {
                    List enumList = EnumUtils.getEnumList(aClass);
                    if(CollectionUtils.isNotEmpty(enumList)){
                        int i  = 0;
                        for (Object o : enumList) {
                            i ++ ;
                            try {
                                String code = (String) MethodUtils.invokeExactMethod(o, "getCode",new Object[]{});
                                String enumName = o.getClass().getName();
                                Object value = MethodUtils.invokeExactMethod(o,"getValue",new Object[]{});
                                String comment = (String) MethodUtils.invokeExactMethod(o,"getComment",new Object[]{});
                                if(code !=null && enumName!= null && value != null && comment != null){
                                    Method getValueMethod = aClass.getMethod("getValue");
                                    Class valueType = getValueMethod.getReturnType();
                                    SysDict sysDict = new SysDict();
                                    sysDict.setParamKey(code);
                                    sysDict.setKeyComment(code);
                                    sysDict.setDataType(valueType.getName());
                                    sysDict.setParamValue(value.toString());
                                    sysDict.setValueComment(comment);
                                    sysDict.setParamOrder(i);
                                    enumsValueList.add(sysDict);
                                }
                            } catch (NoSuchMethodException | InvocationTargetException | IllegalAccessException e) {
                                logger.error(e.getMessage());
                            }
                        }
                    }
                }
            });
        }
        //包扫描出来的枚举排列成map
        enumsValueList.forEach(sysDict -> {
            if(!enumsDictMap.containsKey(sysDict.getParamKey())){
                enumsDictMap.put(sysDict.getParamKey(),new ArrayList<>());
            }
            enumsDictMap.get(sysDict.getParamKey()).add(sysDict);
        });

        Map<String,SysDict> existDictItemMap = new HashMap<>();
        Map<String,SysDict> enumsDictItemMap = new HashMap<>();
        existDicts.forEach(sysDict -> existDictItemMap.put(sysDict.getParamKey()+"_"+sysDict.getParamValue(),sysDict));
        enumsValueList.forEach(sysDict -> enumsDictItemMap.put(sysDict.getParamKey()+"_"+sysDict.getParamValue(),sysDict));
        List<SysDict> updateList = new ArrayList<>();
        List<SysDict> createList = new ArrayList<>();
        List<SysDict> deleteList = new ArrayList<>();
        enumsDictItemMap.forEach((s, sysDict) -> {
            SysDict existDict = existDictItemMap.get(s);
            if(existDict == null){
                //如果数据库中不存在，则创建
                createList.add(sysDict);
            } else if(!sysDict.getValueComment().equals(existDict.getValueComment()) || !sysDict.getDataType().equals(existDict.getDataType())){
                //如果数据库中已经存在，则需要验证是否有改动
                existDict.setValueComment(sysDict.getValueComment());
                existDict.setDataType(sysDict.getDataType());
                existDict.setParamOrder(sysDict.getParamOrder());
                updateList.add(existDict);
            }
        });
        //如果枚举里面没有这个类型，则考虑删除
        existDictItemMap.forEach((s, sysDict) -> {
            SysDict enumsDict = enumsDictItemMap.get(s);
            if(enumsDict == null && enumsDictMap.containsKey(sysDict.getParamKey())){
                deleteList.add(sysDict);
            }
        });

        logger.info("createList:"+JSON.toJSONString(createList));
        if(CollectionUtils.isNotEmpty(createList)){
            try {
                dictService.insertOrUpdateList(createList, SystemUser.root());
            } catch (ServiceException e) {
                logger.error(e.getMessage());
            }
        }
        logger.info("updateList:"+JSON.toJSONString(updateList));
        if(CollectionUtils.isNotEmpty(updateList)){
            try {
                dictService.insertOrUpdateList(updateList, SystemUser.root());
            } catch (ServiceException e) {
                logger.error(e.getMessage());
            }
        }
        logger.info("deleteList:"+JSON.toJSONString(deleteList));
        if(CollectionUtils.isNotEmpty(deleteList)){
            try {
                dictService.deleteByIds(deleteList.stream().map(SysDict::getId).collect(Collectors.toList()));
            } catch (ServiceException e) {
                logger.error(e.getMessage());
            }
        }
    }
}